package de.hska.util;

import org.apache.commons.logging.Log;


/**
 * Hilfsklasse f&uuml;r Logging, um &uuml;ber den aktuellen Thread den
 * Namen der zu protokollierenden Methode zu ermitteln 
 */
public class LogUtil {
	/**
	 * Nummer des Stackframes, in dem die zu protokollierende Methode liegt.<br>
	 * 0: getStackTrace() <br/>
	 * ?: currentThread() <br/>
	 * 1: getMethodName() <br/>
	 * 2: begin/end <br/>
	 * 3: aufrufende Methode <br/>
	 * Bei JDK 5.0 wird currentThread() mitgez&auml;hlt
	 */
	private static final int STACK_NUMBER;
	static {
		int stackNumber = 4;
		try {
			Class.forName("java.lang.Enum");            // ab JDK 5.0
		}
		catch (ClassNotFoundException e) {
			throw new IllegalStateException("At least JDK 5.0 is required");
		}
		
		try {
			Class.forName("java.io.Console");           // ab JDK 6.0
			stackNumber = 3;
		}
		catch (ClassNotFoundException e) {
			// JDK 5.0, aber nicht JDK 6.0
		}

		STACK_NUMBER = stackNumber;
	}

	private static final String BEGIN = MessagesUtil.getMessage("log.begin") + ' ';
	private static final String END = MessagesUtil.getMessage("log.end") + ' ';

	/**
	 * Protokollierung des Methodenanfangs
	 * @param log Log-Objekt
	 * @param args Zus&auml;tzliche Argumente, die im Log-Record durch Komma getrennt werden
	 */
	public static void begin(Log log, Object... args) {
		final String methodName = getMethodName();
		final StringBuilder sb = new StringBuilder(BEGIN + methodName);
		final int anzahlArgs = args.length;
		if (anzahlArgs > 0) {
			sb.append(": ");
			for (int i = 0; i < anzahlArgs; i++) {
				sb.append(args[i]);
				sb.append(", ");
			}
			final int laenge = sb.length();
			sb.delete(laenge-2, laenge-1);
		}
		log.debug(sb.toString());
	}

	/**
	 * Protokollierung des Methodenendes
	 * @param log Log-Objekt
	 * @param args Zus&auml;tzliche Argumente, die im Log-Record durch Komma getrennt werden
	 */
	public static void end(Log log, Object... args) {
		final String methodName = getMethodName();
		final StringBuilder sb = new StringBuilder(END + methodName);
		if (args != null) {
			final int anzahlArgs = args.length;
			if (anzahlArgs > 0) {
				sb.append(": ");
				for (int i = 0; i < anzahlArgs; i++) {
					sb.append(args[i]);
					sb.append(", ");
				}
				final int laenge = sb.length();
				sb.delete(laenge-2, laenge-1);
			}
		}
		log.debug(sb.toString());
	}

	/**
	 * Protokollierung des Methodenendes im Fehlerfall
	 * @param log Log-Objekt
	 * @param e ausgel&ouml;ste Exception
	 */
	public static void endError(Log log, Exception e) {
		log.error(END + getMethodName() + ": " + e.getMessage());
	}
	
	/**
	 * Protokollierung des Methodenendes im Fehlerfall
	 * @param log Log-Objekt
	 * @param msg zus&auml;tzlicher Text
	 */
	public static void endError(Log log, String msg) {
		log.error(END + getMethodName() + ": " + msg);
	}
	
	/**
	 * Protokollierung des Methodenendes mit einer Warnung
	 * @param log Log-Objekt
	 * @param e ausgel&ouml;ste Exception
	 */
	public static void endWarn(Log log, Exception e) {
		log.warn(END + getMethodName() + ": " + e.getMessage());
	}
	
	/**
	 * Protokollierung des Methodenendes mit einer Warnung
	 * @param log Log-Objekt
	 * @param msg zus&auml;tzlicher Text
	 */
	public static void endWarn(Log log, String msg) {
		log.warn(END + getMethodName() + ": " + msg);
	}
	
	/**
	 * @return Name der zu protokollierenden Methode
	 * @see LogUtil#STACK_NUMBER
	 */
	private static String getMethodName() {
		final StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
		return stackTraceElements[STACK_NUMBER].getMethodName();
	}
}
